<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>函数</title>
    <meta charset="utf-8">
</head>
<body>
<script type="text/javascript">
/** 函数 只定义一次,但可以被执行或调用任意次。当调用该函数时，会执行函数内的代码 **/
//    创建函数 (在JS里不能取相同名字的函数名，后面会覆盖前面的函数)
//        声明式
//          function 函数名(参数1，参数2……){ <语句块>[ return 返回值] }
//        表达式(匿名函数)
//          var Square = function(x){ return x*x; };    //把匿名函数赋值给变量
//        Function:构造函数 参考'对象.html'-面向对象方式-工厂方式
//          var box = new Function('a','b','return a+b');//'参数名','参数名','最后一个放函数体'
//          var gz = new Square('参数'); // 用之前创建的函数当构造函数 规范首字母大写
//        区别:对于声明式,js解析器会优先读取,提升到该函数所在作用域的最开头
//          而函数表达式，如同定义其它基本类型的变量一样，只在执行到某一句时才会对其进行解析。
//          所以两者区别主要在于函数执行语句放在函数定义语句之前的情况，如果写在函数声明之前的话不会报错，但是写在函数表达式之前会报错。
//    函数调用
//        1.作为函数 2.作为方法 3.作为构造函数 4.通过它们的call()和apply()方法间接调用
//            1.直接调用  myfun();
//            2.事件处理中调用   <div onclick=“myfun()”></div>
//            3.将函数的返回值赋给变量 (针对有返回值的函数)   var t = myfun();
//            计算阶乘的递归函数（调用自身函数） x!的值是从x到x递减（步长为1）的值得累乘
//            function factorial(x) {if(x<=1){return 1;} else{return x*factorial(x-1);} }
//            //函数表达式可以定义以后立即使用
//            var ten = (function (x) {return x*x;}(10));   //将返回值赋给ten
//            //函数自调用方式 (匿名函数)(实参)     可在function前增加 ! 或 + 或 void 或者用一对圆括号包裹
//                  (function (a){alert(a)})(11);
//            //在js中函数可以嵌套其他函数
//            function a(a,b) {function b(a,b) {return a-b;}}
//    arguments:一个对应于传递给函数的参数的类数组对象
//      不是一个Array.它类似于Array,但除了length属性和索引元素之外没有任何Array属性
//      arguments.callee    指向当前执行的函数
//      arguments.length    指向传递给当前函数的参数数量
//      arguments[@@iterator]   返回一个新的Array迭代器对象，该对象包含参数中每个索引的值
//      function box(num){
//          if(num <= 1){return 1}
//          else {return num * arguments.callee(num-1)} //使用arguments.callee调用函数自身，实现递归
//      }
//    参数
//      形参个数比实参多时,少的实参都按照undefined处理
//        function sum(a,b){ 
//             console.log(a+b)  //1+undefined=nan
//             console.log(sum.length) // 参数的个数
//           } 
//        sum(1);    //NaN
//      实参个数比形参多时,多的实参自动忽略
//        function output(a){ console.log(a) }
//        output(1,4);  //1
//      不定参
//            function sum(){
//                var result = 0;
//                arguments.push(5);        // 伪数组不是数组，所有不能调用数组的方法
//                for(var i = 0, len = arguments.length; i < len; i++){
//                    result += arguments[i];
//                }
//                return result;  //1+2+3+4+8=18
//            }
//            alert(sum(1,2,3,4,8));
//    返回值
//          function show(a, b, c){
//              return {sum: a + b + c, multiply: a * b * c};   //返回多个值时可以把值放到数组或者对象（建议）里再返回
//          }
//          document.writeln(show(4,2,3).sum);      //  9
//    作为值的函数
//      函数在Javascript中,函数不仅是一种语法,也是值.可以将函数赋值给变量,存储在对象的属性或数组的元素中,作为参数传给另外一个函数等
//            赋值给变量
//            function square(x){ return x*x; }
//            var s = square;//现在s和square指同一个函数 浅拷贝
//            square(4); //16
//            s(4); //16
//            赋值给对象属性
//            var o = {square:function(x){ return x*x; }};  //创建一个对象，square属性是个函数
//            var y = o.square(16); //256
//            函数表达式可以作为参数传给其他函数
//            a.sort(function (a,b) {return a-b;});

/** 作用域 **/
//作用域就是变量与函数的可访问范围，作用域控制着变量与函数的可见性和生命周期。
//    用var和function声明的会被提升 函数层级>arguments>var
//      console.log(a);  // function
//      function a(){};
//      var a = 10;
//      console.log(a); //10
//      等同于
//      function a(){}
//      var a // 与函数生声明重名,被忽略
//      console.log(a)
//      a =10
//      console.log(a)
//    全局作用域（Global Scope）：在代码中任何地方都能访问到的对象拥有全局作用域
//        拥有全局作用域的情形
//          1.最外层函数和在最外层函数外定义的变量拥有全局作用域
//                var aut="sunny";
//                function dos() {
//                    var blo="jessice";
//                    function  inn() {
//                        alert(blo);
//                    }
//                    inn();
//                }
//                alert(aut);//sunny  全局属性（变量）
//                alert(blo);//脚本错误
//                dos();//jessica 全局函数
//                inn();//脚本错误
//          2.所有末定义直接赋值(没有var关键字)的变量自动声明为拥有全局作用域
//                function dos() {
//                    var aut="sunny";
//                    blo="jessica";
//                    alert(aut);
//                }
//                dos();//sunny   全局函数（方法）
//                alert(blo);//jessica     全局属性（变量）
//                alert(aut);//脚本错误
//          3.所有window对象的属性拥有全局作用域例。如window.name、window.location
//    局部作用域：只在固定的代码片段内可访问到，最常见的的就是在函数内部，可称为函数作用域
//      函数体内的变量,函数声明（var声明的变量）会提前到函数体顶部,赋为undefined，同时变量初始化还在原来位置
//      变量取值是就近原则
//                function dos() {
//                    var aut="sunny";
//                    function ddd() {
//                        var blo="jessica";
//                        alert(aut);
//                    }
//                    ddd();
//                }
//                alert(sunny);//脚本错误  局部变量
//                alert(ddd());//脚本错误  局部函数

/** 作用域面试题 **/
//var scope="global";
//function t(){
//    console.log(scope); //undefined   下一行代码声明了此变量，声明提升了，覆盖了全局变量，但没赋值
//    var scope="local";  //
//    console.log(scope); //local
//}
//t();
//---------------------------------------------------------------------------
//var a;
//function fun() {
//    a = "global";
//}
//fun();
//console.log(a); //global    a是全局，在fun()里赋值，依然是全局
//---------------------------------------------------------------------------
//var a=1;
//function main(){
//    var a=2;//局部变量  覆盖了全局定义a
//    console.log(a); //2
//}
//main();
//console.log(a); //1     在main()覆盖了，但var提升的是定义，赋值在function后，a=1在function后
//---------------------------------------------------------------------------
//        var num = 10;
//        function show(){
//            document.writeln(num);      //10  下面的代码只是赋值，没有覆盖全局的定义
//            num = 20;         //全局变量更改成20
//            document.writeln(num);      //20
//        }
//        show();
//        document.writeln(num);        //20
</script>
不定参数实例
<div style="width:200px; height: 200px; background-color: darkgrey;" id="div1"></div>
<script type="text/javascript">
    var oDiv = document.getElementById("div1");     //选中div1
    function cssStyle(element, attr, value){
        if(arguments.length === 2 ){ //如果传的时两个参数
            if(typeof attr === "string") {  //且第2个为字符串
                return element.style[attr];//返回 传入对象的属性值
            }else if(typeof attr === "object"){ //第二个为对象
                for(var key in attr){   //遍历出attr的属性名
                    if(isNaN(parseInt(attr[key]))){ //如果不是数字(那就不是宽高值)进入此循环
                        element.style[key] = attr[key]; //给对象加属性值
                    }else{//如果是数字进入此循环
                        element.style[key] = parseInt(attr[key]) + "px";//设置传入对象的属性值
                    }
                }
            }
        }else if(arguments.length === 3){//如果传的时3个参数，且第一个为字符串(对象)
            element.style[attr] = value;//设置传入对象的属性值
            return element.style[attr];
        }
    }
    console.log(cssStyle(oDiv, "height"));        //200   因为传入了3个参数，，进入if语句,返回div1本身就设置的height
    console.log(cssStyle(oDiv, "width", "400px"));    //400   因为传入了3个参数，进入else if语句
    cssStyle(oDiv, {width: 800, height: "700","backgroundColor": "red"});  //800 700 因为传入了2个参数,
</script>

</body>
</html>